﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace ConfigMerger
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {

               
                if (args == null || args.Length < 4)
                {
                    Console.WriteLine("ConfigMerger.exe require at least 4 parameters: location, the $(Configuration) value, the to-be-updated/created .config file and prefix for common config");
                }
                else
                {
                    string str1 = Path.Combine(args[0],args[1] + "." + args[2]);
                    if (!File.Exists(str1))
                    {
                        Console.WriteLine("can't find the specified .config file: " + str1);
                    }
                    else
                    {
                        string str2 = Path.Combine(args[0], args[3] + "." + args[2]);
                        if (!File.Exists(str2))
                        {
                            Console.WriteLine("can't find the .config file: " + str2);
                        }
                        else
                        {
                            XElement commonDocument;
                            try
                            {
                                commonDocument = XElement.Load(str2);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message);
                                return;
                            }
                            XElement xelement;
                            try
                            {
                                xelement = XElement.Load(str1);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message);
                                return;
                            }
                            IEnumerable<XElement> configEnvPart;
                            try
                            {
                                configEnvPart = xelement.Elements();
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message);
                                return;
                            }
                            if (configEnvPart == null)
                            {
                                Console.WriteLine("no common things");
                            }
                            else
                            {
                                Program.UpdateSettings(commonDocument, configEnvPart);

                                var webconfigpath = Path.Combine(args[0],args[2]);

                                if (!System.IO.File.Exists(webconfigpath))
                                {
                                    using (TextWriter tw = new StreamWriter(webconfigpath))
                                    {
                                        var line1 = "<?xml version='1.0'?>";
                                        var line2 = "<configuration xmlns='http://schemas.microsoft.com/.NetConfiguration/v2.0'/>";
                                        tw.WriteLine(line1);
                                        tw.WriteLine(line2);
                                    }
                                }

                                commonDocument.Save(webconfigpath);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(((object)ex).ToString());
            }
        }

        private static void UpdateSettings(XElement commonDocument, IEnumerable<XElement> configEnvPart)
        {
            for (int i = 0; i < Enumerable.Count<XElement>(configEnvPart); ++i)
            {
                switch (Enumerable.ElementAt<XElement>(configEnvPart, i).Name.LocalName)
                {
                    case "connectionStrings":
                        XElement oldCSs = Enumerable.First<XElement>(commonDocument.Elements(), (Func<XElement, bool>)(x => x.Name.LocalName == "connectionStrings"));
                        if (oldCSs != null)
                        {
                            Program.UpdateConnectionStrings(oldCSs, Enumerable.ElementAt<XElement>(configEnvPart, i).Elements());
                            break;
                        }
                        else
                            break;
                    case "appSettings":
                        XElement oldASs = Enumerable.First<XElement>(commonDocument.Elements(), (Func<XElement, bool>)(x => x.Name.LocalName == "appSettings"));
                        if (oldASs != null)
                        {
                            Program.UpdateAppSettings(oldASs, Enumerable.ElementAt<XElement>(configEnvPart, i).Elements());
                            break;
                        }
                        else
                            break;
                    default:
                            break;
                }
            }
        }

        private static void UpdateAppSettings(XElement oldASs, IEnumerable<XElement> newASs)
        {
            List<XElement> list = Enumerable.ToList<XElement>((IEnumerable<XElement>)Enumerable.OrderBy<XElement, string>(Enumerable.Where<XElement>(oldASs.Descendants(), (Func<XElement, bool>)(el => el.Name.LocalName == "add")), (Func<XElement, string>)(el => el.Attribute((XName)"key").Value)));
            using (List<XElement>.Enumerator enumerator = Enumerable.ToList<XElement>((IEnumerable<XElement>)Enumerable.OrderBy<XElement, string>(Enumerable.Where<XElement>(newASs, (Func<XElement, bool>)(el => el.Name.LocalName == "add")), (Func<XElement, string>)(el => el.Attribute((XName)"key").Value))).GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    XElement newItem = enumerator.Current;
                    if (Enumerable.Count<XElement>((IEnumerable<XElement>)list) == 0)
                    {
                        oldASs.Add((object)newItem);
                    }
                    else
                    {
                        XElement xelement = Enumerable.FirstOrDefault<XElement>(Enumerable.Where<XElement>((IEnumerable<XElement>)list, (Func<XElement, bool>)(oel => oel.Attribute((XName)"key").Value == newItem.Attribute((XName)"key").Value)));
                        if (xelement == null)
                            oldASs.Add((object)newItem);
                        else
                            xelement.Attribute((XName)"value").Value = newItem.Attribute((XName)"value").Value;
                    }
                }
            }
        }

        private static void UpdateConnectionStrings(XElement oldCSs, IEnumerable<XElement> newCSs)
        {
            List<XElement> list = Enumerable.ToList<XElement>((IEnumerable<XElement>)Enumerable.OrderBy<XElement, string>(Enumerable.Where<XElement>(oldCSs.Descendants(), (Func<XElement, bool>)(el => el.Name.LocalName == "add")), (Func<XElement, string>)(el => el.Attribute((XName)"name").Value)));
            using (List<XElement>.Enumerator enumerator = Enumerable.ToList<XElement>((IEnumerable<XElement>)Enumerable.OrderBy<XElement, string>(Enumerable.Where<XElement>(newCSs, (Func<XElement, bool>)(el => el.Name.LocalName == "add")), (Func<XElement, string>)(el => el.Attribute((XName)"name").Value))).GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    XElement newItem = enumerator.Current;
                    if (Enumerable.Count<XElement>((IEnumerable<XElement>)list) == 0)
                    {
                        oldCSs.Add((object)newItem);
                    }
                    else
                    {
                        XElement xelement = Enumerable.FirstOrDefault<XElement>(Enumerable.Where<XElement>((IEnumerable<XElement>)list, (Func<XElement, bool>)(oel => oel.Attribute((XName)"name").Value == newItem.Attribute((XName)"name").Value)));
                        if (xelement == null)
                        {
                            oldCSs.Add((object)newItem);
                        }
                        else
                        {
                            xelement.Attribute((XName)"connectionString").Value = newItem.Attribute((XName)"connectionString").Value;
                            if (xelement.Attribute((XName)"providerName") != null && newItem.Attribute((XName)"providerName") != null)
                                xelement.Attribute((XName)"providerName").Value = newItem.Attribute((XName)"providerName").Value;
                        }
                    }
                }
            }
        }

      
        
    }
}
